package controller

import (
	"fmt"
	"gitee.com/saxon134/go-utils/saData"
	"gitee.com/saxon134/go-utils/saData/saHit"
	"gitee.com/saxon134/go-utils/saData/saTime"
	"gitee.com/saxon134/go-utils/saOrm"
	"gitee.com/saxon134/workflow/api"
	"gitee.com/saxon134/workflow/db"
	"gitee.com/saxon134/workflow/db/chat"
	"gitee.com/saxon134/workflow/db/demand"
	"gitee.com/saxon134/workflow/db/job"
	"gitee.com/saxon134/workflow/db/user"
	"gitee.com/saxon134/workflow/enum"
	"gitee.com/saxon134/workflow/errs"
	"gitee.com/saxon134/workflow/interface/ioDemand"
	"gitee.com/saxon134/workflow/utils"
	"gorm.io/gorm"
	"strings"
	"time"
)

func DemandList(c *api.Context) (resp *api.Response, err error) {
	in := new(ioDemand.ListRequest)
	c.Bind(in)

	var usrObj = new(user.TblUser)
	db.MySql.Table(user.TBNUser).Where("id = ?", c.Account.Id).First(usrObj)

	var query = db.MySql.Table(demand.TBNDemand)

	if in.Keyword != "" {
		query.Where(fmt.Sprintf(`title like '%%%s%%'`, in.Keyword))
	}

	//全部状态
	if in.Status == -100 {

	} else if in.Status != 0 {
		query.Where("status = ?", in.Status)
	} else {
		query.Where("(status in(1,20,30) and deadline is not null)")
	}

	if in.P > 0 {
		query.Where("p = ?", in.P)
	}

	//暂时关闭权限
	if false {
		//管理员，可以指定人员查询
		if strings.Contains(usrObj.Roles, "1") {
			if in.UserId > 0 {
				query.Where(fmt.Sprintf(`partners like '%%,%d,%%'`, in.UserId))
			}
		} else
		//经理，可以看到自己参与项目下所有需求
		if strings.Contains(usrObj.Roles, "2") {
			var proIdAry = make([]int64, 0, 10)
			db.MySql.Raw(fmt.Sprintf("select project_id from project_rs where user_id = %d and status = 1;", c.Account.Id)).Scan(&proIdAry)
			if len(proIdAry) == 0 {
				return &api.Response{Result: nil}, nil
			}
			query.Where("project_id in ?", proIdAry)
		} else
		//其他，只能查看自己参与的需求
		{
			query.Where(fmt.Sprintf(`partners like '%%,%d,%%'`, c.Account.Id))
		}
	}

	//仅查看跟我相关的
	if in.OnlyMe {
		query.Where(fmt.Sprintf(`(partners like '%%,%d,%%' or leader = %d)`, c.Account.Id, c.Account.Id))
	}

	//排序
	if c.Sort.Key != "" {
		query.Order(saData.SnakeStr(c.Sort.Key) + saHit.Str(c.Sort.Desc, " desc", " asc"))
	} else
	//默认按优先级
	{
		query.Order("deadline asc, p asc, status asc,  id desc")
	}

	//分页总数
	if c.Paging.Total <= 0 {
		err = query.Count(&c.Paging.Total).Error
		if err != nil {
			return nil, errs.New(err)
		}
	}

	//无更多数据
	if c.Paging.Total <= int64(c.Paging.Offset) {
		return &api.Response{Result: nil}, nil
	}

	//需求基本信息
	var ary = make([]*demand.TblDemand, 0, c.Paging.Limit)
	query.Offset(c.Paging.Offset).Limit(c.Paging.Limit)
	err = query.Find(&ary).Error
	if db.MySql.IsError(err) {
		return nil, errs.New(err)
	}

	//数据空
	if len(ary) == 0 {
		return &api.Response{Result: nil}, nil
	}

	//返回数据结构
	var resAry = make([]*ioDemand.ListItem, 0, len(ary))

	//获取任务完成数量
	var idAry = make([]int64, 0, len(ary))
	for _, v := range ary {
		idAry = append(idAry, v.Id)
	}
	var jobs = make([]JobCnt, 0, len(ary)*2)
	err = db.MySql.Raw("select demand_id, status, count(*) cnt from job where demand_id in ? group by demand_id, status", idAry).Find(&jobs).Error
	if db.MySql.IsError(err) {
		return nil, errs.New(err)
	}

	//组装返回数据
	for _, v := range ary {
		var item = &ioDemand.ListItem{
			TblDemand: v,
			DoneJob:   0,
			TodoJob:   0,
		}
		for _, j := range jobs {
			if j.DemandId == item.Id {
				if j.Status == enum.WorkPending || j.Status == enum.WorkProcessing || j.Status == enum.WorkTesting {
					item.TodoJob++
				} else if j.Status == enum.WorkDone || j.Status == enum.WorkOnline {
					item.DoneJob++
				}
			}
		}
		resAry = append(resAry, item)
	}

	return &api.Response{Result: resAry}, nil
}

func DemandDetail(c *api.Context) (resp *api.Response, err error) {
	var in = map[string]interface{}{}
	c.Bind(in)
	var demandId = saData.Int64(in["id"])
	if demandId <= 0 {
		return nil, errs.New(errs.ErrorParams)
	}

	var obj = new(demand.TblDemand)
	db.MySql.Where("id = ?", demandId).First(obj)
	if obj.Id <= 0 {
		return nil, errs.New(errs.ErrorNotExisted)
	}

	//返回数据
	var res = ioDemand.DetailResponse{
		TblDemand: obj,
		Jobs:      make([]*job.TblJob, 0, 10),
	}

	//任务基本信息
	db.MySql.Table(job.TBNJob).Where("demand_id = ?", demandId).Find(&res.Jobs)

	//编辑权限
	{
		res.Disabled.Title = true
		res.Disabled.Detail = true
		res.Disabled.Partners = true
		res.Disabled.Deadline = true
		res.Disabled.Project = true
		res.Disabled.Status = map[int]bool{}
		res.Disabled.P = true

		//-1-废弃 1-待确认 2-开发中 3-测试中 4-已完成 5-已上线
		for i := -1; i <= 5; i++ {
			res.Disabled.Status[i] = true
		}

		//当前用户
		var usrObj = new(user.TblUser)
		db.MySql.Table(user.TBNUser).Where("id = ?", c.Account.Id).First(usrObj)

		//待确认
		if res.Status == enum.WorkPending {
			//产品、管理可以编辑
			if strings.Contains(usrObj.Roles, "1") || strings.Contains(usrObj.Roles, "2") || strings.Contains(usrObj.Roles, "3") {
				res.Disabled.Title = false
				res.Disabled.Detail = false
				res.Disabled.Partners = false
				res.Disabled.Deadline = false
				res.Disabled.Project = false
				res.Disabled.P = false

				for i := -1; i <= 5; i++ {
					res.Disabled.Status[i] = false
				}
			}
		} else
		//开发中
		if res.Status == enum.WorkProcessing {
			//管理有权限改状态、优先级、截止时间、参与人
			if strings.Contains(usrObj.Roles, "1") || strings.Contains(usrObj.Roles, "2") {
				for i := -1; i <= 5; i++ {
					res.Disabled.Status[i] = false
				}
				res.Disabled.Partners = false
				res.Disabled.Deadline = false
				res.Disabled.P = false
			}

			//开发有权限修改状态
			if strings.Contains(usrObj.Roles, "4") {
				res.Disabled.Status[3] = false
				res.Disabled.Status[4] = false
			}
		} else
		//测试中
		if res.Status == enum.WorkTesting {
			//管理、测试人员有权限改状态
			if strings.Contains(usrObj.Roles, "1") || strings.Contains(usrObj.Roles, "2") || strings.Contains(usrObj.Roles, "5") {
				res.Disabled.Status[-1] = false
				res.Disabled.Status[1] = false
				res.Disabled.Status[2] = false
				res.Disabled.Status[4] = false
			}
		} else
		//废弃
		if res.Status == enum.WorkAbandon {
			//管理有权限改状态
			if strings.Contains(usrObj.Roles, "1") || strings.Contains(usrObj.Roles, "2") {
				res.Disabled.Status[-1] = false
				res.Disabled.Status[1] = false
			}
		}
	}

	return &api.Response{Result: res}, nil
}

func DemandAdd(c *api.Context) (resp *api.Response, err error) {
	in := new(ioDemand.SaveRequest)
	c.Bind(in)
	if in.Title == "" || in.ProjectId <= 0 {
		return nil, errs.New(errs.ErrorParams)
	}

	if in.TblDemand.Id > 0 {
		return nil, errs.New("不支持修改")
	}

	//同名需求
	var existId int64
	db.MySql.Raw("select id from demand where project_id = ? and title = ? limit 1", in.ProjectId, in.Title).Scan(existId)
	if existId > 0 && existId != in.Id {
		return nil, errs.New(errs.ErrorExisted)
	}

	//默认值
	in.Leader = saHit.Int64(in.Leader > 0, in.Leader, c.Account.Id)
	in.P = saHit.Int(in.P > 0, in.P, 2)
	in.Status = saHit.Int(in.Status > 0, in.Status, 1)
	in.TblDemand.CreateAt = saOrm.Now()

	//参与者
	var partners = saData.IdsToAry(in.TblDemand.Partners)

	//任务负责人也加入到参与人
	for _, v := range in.Jobs {
		if v.Status > 0 {
			partners = saData.AppendId(partners, v.Leader)
			if v.Leader <= 0 {
				return nil, errs.New("任务责任人不能空")
			}
		}
	}
	in.TblDemand.Partners = saData.AryToIds(partners, true)

	//任务处理
	var addJobAry = make([]*job.TblJob, 0, len(in.Jobs))
	if len(in.Jobs) > 0 {
		for _, v := range in.Jobs {
			if v.Status > 0 {
				v.ProjectId = in.TblDemand.ProjectId
				v.DemandId = in.TblDemand.Id
				v.Deadline = in.TblDemand.Deadline
				v.P = in.TblDemand.P
				v.CreateAt = saOrm.Now()
				addJobAry = append(addJobAry, v)
			}
		}
	}

	//聊天处理
	var addChatAry = make([]*chat.TblChat, 0, len(in.Chats))
	if len(in.Chats) > 0 {
		for _, v := range in.Chats {
			if v.Status == enum.Enable {
				v.DemandId = in.TblDemand.Id
				v.CreateAt = saOrm.Now()
				v.Creator = c.Account.Id
				v.Level = saHit.Int(v.Level == 2, 2, 1)
				v.DemandStatus = in.TblDemand.Status
				addChatAry = append(addChatAry, v.TblChat)
			}
		}
	}

	//保存数据
	err = db.MySql.Transaction(func(tx *gorm.DB) error {

		//保存需求基本数据
		err = tx.Save(in.TblDemand).Error
		if err != nil {
			return errs.New(err)
		}

		//保存任务
		if len(addJobAry) > 0 {
			for _, v := range addJobAry {
				v.ProjectId = in.TblDemand.ProjectId
				v.DemandId = in.TblDemand.Id
				v.CreateAt = saOrm.Now()
			}
			err = tx.Save(addJobAry).Error
			if err != nil {
				return errs.New(err)
			}
		}

		//保存聊天
		if len(addChatAry) > 0 {
			for _, v := range addChatAry {
				v.DemandId = in.TblDemand.Id
			}

			err = tx.Save(addChatAry).Error
			if err != nil {
				return errs.New(err)
			}

			var addResourceAry = make([]*chat.TblResource, 0, len(in.Chats))
			for _, v := range in.Chats {
				if v.Status == enum.Enable {
					var id int64
					for _, c := range addChatAry {
						if c.Content == v.Content && c.Status == v.Status {
							id = c.Id
							break
						}
					}

					if id > 0 {
						for i, r := range v.Resources {
							if r.Status == enum.Enable {
								r.ChatId = id
								r.CreateAt = saOrm.Now()
								r.Type = utils.FormatContent(r.Type, r.Content) //格式化类型
								r.Seq = i
								addResourceAry = append(addResourceAry, r)
							}
						}
					}
				}
			}

			if len(addResourceAry) > 0 {
				err = tx.Save(addResourceAry).Error
				if err != nil {
					return errs.New(err)
				}
			}
		}

		return nil
	})
	if err != nil {
		return nil, errs.New(err)
	}
	return &api.Response{Result: nil}, nil
}

func DemandUpdate(c *api.Context) (resp *api.Response, err error) {
	in := new(ioDemand.UpdateRequest)
	c.Bind(in)
	if in.DemandId <= 0 || in.Key == "" {
		return nil, errs.New(errs.ErrorParams)
	}

	if saData.InArray(in.Key, []string{"projectId", "leader", "title", "status", "p", "deadline", "detail"}) == true {
		var sql = fmt.Sprintf("update demand set %s = '%s' where id = %d;\n", in.Key, in.Value, in.DemandId)

		if in.Key == "status" {
			var status = saData.Int(in.Value)
			var now = time.Now().Format(saTime.FormatDefault)

			//所有任务必须是已完成
			if status == enum.WorkDone || status == enum.WorkOnline {
				var unfinishedId int64
				err = db.MySql.Raw("select id from job where demand_id = ? and (status = 1 or status = 20 or status = 30) limit 1", in.DemandId).
					Scan(&unfinishedId).Error
				if db.MySql.IsError(err) {
					return nil, errs.New(err)
				}

				if unfinishedId > 0 {
					return nil, errs.New("存在未完成任务")
				}
			}

			if status == enum.WorkProcessing {
				sql += fmt.Sprintf("update demand set confirm_at = '%s', dev_at = '%s' where id = %d;\n", now, now, in.DemandId)
			} else if status == enum.WorkTesting {
				sql += fmt.Sprintf("update demand set test_at = '%s' where id = %d;\n", now, in.DemandId)
			} else if status == enum.WorkDone {
				sql += fmt.Sprintf("update demand set done_at = '%s' where id = %d;\n", now, in.DemandId)
			} else if status == enum.WorkOnline {
				sql += fmt.Sprintf("update demand set online_at = '%s' where id = %d;\n", now, in.DemandId)
			} else if status == enum.WorkAbandon {
				//要将关联任务都关闭
				sql += fmt.Sprintf("update job set status = -1 where demand_id = %d;\n", in.DemandId)
			}
		} else
		//需要联动修改关联任务优先级
		if in.Key == "p" {
			sql += fmt.Sprintf("update job set p = %s where demand_id = %d;\n", in.Value, in.DemandId)
		} else
		//需要联动修改关联任务截止日期
		if in.Key == "deadline" {
			sql += fmt.Sprintf("update job set deadline = '%s' where demand_id = %d;\n", in.Value, in.DemandId)
		}

		err = db.MySql.Exec(sql).Error
		if err != nil {
			return nil, errs.New(err)
		}
		return &api.Response{Result: nil}, nil
	}

	if in.Key == "partners" {
		var idAry = saData.IdsToAry(in.Value)
		err = db.MySql.Exec("update demand set partners = ? where id = ?", saData.AryToIds(idAry, true), in.DemandId).Error
		if err != nil {
			return nil, errs.New(err)
		}

		return &api.Response{Result: nil}, nil
	}

	return nil, errs.New(errs.ErrorParams)
}
